#include <thread>

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <singleton_mocker.h>

#define protected public
#define private public
#include "my_socket_server.h"
#include "my_socket_client.h"
#include "service_registry.h"
#undef protected
#undef private

using namespace testing;

class MockServiceRegistry : public ServiceRegistry {
public:
    MOCK_METHOD(void, AddService, (const sptr<IService> &service), (override));
    MOCK_METHOD(void, RemoveService, (const sptr<IService> &service), (override));
    MOCK_METHOD(std::string, DispatchMessage, (int id, const std::string &message), (override));
};

class MySocketServerTest : public Test {
public:
    static void SetUpTestSuite()
    {
        server = MySocketServer::GetInstance();
        client = MySocketClient::GetInstance();
    }

    static void TearDownTestSuite()
    {
    }

    static inline sptr<MySocketServer> server = nullptr;
    static inline sptr<MySocketClient> client = nullptr;
    static inline std::unique_ptr<std::thread> thread = nullptr;
};

TEST_F(MySocketServerTest, Start)
{
    ASSERT_EQ(server->Start(23456), 0);
}

TEST_F(MySocketServerTest, Run)
{
    {
        SingletonMocker<ServiceRegistry, MockServiceRegistry> m;
        thread = std::make_unique<std::thread>([]() { server->Run(); });
        sleep(1);

        EXPECT_CALL(*m.Mock(), DispatchMessage(123, "456")).Times(1).WillOnce(Return("ok"));
        client->Connect("127.0.0.1", 23456);
        client->Send({.id = 123, .message = "456"});
        ASSERT_EQ(client->Recv(), "ok");
        client->Disconnect();
    }
}

TEST_F(MySocketServerTest, Stop)
{
    server->Stop();
    thread->join();
}
